import core.util.OrderedSet;
import core.util.ArrayList;

class HashMap {

	/**
	 * Initializes the map.
	 *
	 * @param
	 * elements (object) [optional] Initial key-value mappings.
	 */
	this.HashMap = function(elements) {
		this.elements = elements || {};
		this.elementCount = 0;
	}

	/**
	 * @param
	 * key (string)
	 * value (variant)
	 */
	this.set = function(key, value) {
		if (!this.hasKey(key)) {
			++this.elementCount;
		}
		this.elements[key] = value;
	}

	/**
	 * Returns the value by key.
	 *
	 * @param
	 * key (string) The key associated with value.
	 *
	 * @return variant
	 */
	this.get = function(key) {
		return this.elements[key];
	}

	/**
	 * Removes the map value by key.
	 *
	 * @param
	 * key (string) The key associated with value.
	 */
	this.remove = function(key) {
		if (this.hasKey(key)) {
			delete this.elements[key];
			this.elementCount--;
		}
	}

	/**
	 * Checks whether the map has the specified key.
	 *
	 * @param
	 * key (string)
	 *
	 * @return bool
	 */
	this.hasKey = function(key) {
		return (key in this.elements);
	}

	/**
	 * Clears the map.
	 */
	this.clear = function() {
		delete this.elements;
		this.elements = {};
	}

	/**
	 * Returns the number of key-value mappings in the map.
	 * @return int
	 */
	this.size = function() {
		return this.elementCount;
	}

	/**
	 * Returns the collection of keys in the map. 
	 * @return OrderedSet
	 */
	this.getKeys = function() {
		// TODO: optimize
        var keys = new OrderedSet();
        var elements = this.elements;
        for (var key in elements) {
            if (elements.hasOwnProperty(key)) {
                keys.add(key);
            }
        }
        return keys;
	}

	/**
	 * Returns the collection of map values.
	 */
	this.getValues = function() {
		// TODO: optimize
		var values = new ArrayList();
        var elements = this.elements;
        for (var key in elements) {
            if (elements.hasOwnProperty(key)) {
                values.add(elements[key]);
            }
		}
		return values;
	}

    this.entries = function () {
        // TODO: optimize
        var entries = new ArrayList();
        var elements = this.elements;
        for (var key in elements) {
            if (elements.hasOwnProperty(key)) {
                entries.add({key:key,value:elements[key]});
            }
        }
        return entries;
    }

	/**
	 * Returns the map as native JavaScript object.
	 * @return object
	 */
	this.toObject = function() {
		return this.elements;
	}
}
